package jp.ac.aiit.yc.sww.messaging;

import flex.messaging.FlexContext;
import flex.messaging.MessageBroker;
import flex.messaging.MessageClient;
import flex.messaging.MessageClientListener;
import flex.messaging.messages.AsyncMessage;
import flex.messaging.util.UUIDUtils;
import java.util.*;

import static jp.ac.aiit.yc.sww.constant.Constants.*;
import javax.servlet.ServletContext;

import jp.ac.aiit.yc.sww.database.*;
import jp.ac.aiit.yc.sww.database.dao.*;
import jp.ac.aiit.yc.sww.database.dto.DrawDto;
import jp.ac.aiit.yc.sww.database.dto.LoginDto;
import jp.ac.aiit.yc.sww.database.dto.ModeDto;
import jp.ac.aiit.yc.sww.database.dto.NoteDataDto;
import jp.ac.aiit.yc.sww.database.dto.PresentDto;
import jp.ac.aiit.yc.sww.database.dto.SwwDtoIF;


public class ClientWatcher implements MessageClientListener{

	@Override
	public void messageClientCreated(MessageClient msgClient) {

		//Added by Kato 2009/01/17 try...catchを追加
		try{

			String userName = msgClient.getFlexSession().getUserPrincipal().getName();
			System.out.println(new Date().toString() + " " + userName + " has joined.");


			Map<String, String> headers = new HashMap<String, String>();
			headers.put(HEADER_USER, userName);
			headers.put(HEADER_ROOM, msgClient.getDestinationId());

//			// loginイベントをDBに登録
//			System.out.println((new Date()).toString() + " loginのDaoとDtoをDBに登録 ");
			LoginDto loginDto = new LoginDto();
			loginDto.setUser(userName);
			loginDto.setMeeting_room_id(msgClient.getDestinationId());
			LoginDao loginDao = new LoginDao();
			loginDao.setHeaders(headers);

//			// 戻り値は結果行の有無なので、executeUpdateの戻り値は常にfalse
//			System.out.println((new Date()).toString() + " DatabaseManagerを作成");
			DatabaseManager dm = new DatabaseManager();
			//ログインをDBに登録
			boolean result = dm.register(loginDto, loginDao);
//			System.out.println((new Date()).toString() + " dm.register(loginDto, loginDao)=" + result);


			// 値を取得できなければgetAttributeはnullを返す
			
			//セッションから現在情報取得
			Object pageStatOBj = FlexContext.getServletContext().getAttribute(SESSION_PAGESTATUS);
			//現在情報から現在のドキュメントとページを取得
			if(pageStatOBj!=null & pageStatOBj instanceof PageStatus){
				System.out.println(new Date().toString() + " SESSION_PAGESTATUS has pageStatOBj.");
				PageStatus pageStatus = (PageStatus)pageStatOBj;

				// 最初にはpageをセッションから取得
				List<Object> msgList = new ArrayList<Object>();
				msgList.add( Integer.toString(pageStatus.getDocID()));
				msgList.add( Integer.toString(pageStatus.getPageID()));
				
				
				System.out.println(new Date().toString() + " docID:pageID=" + pageStatus.getDocID() + ":" + pageStatus.getPageID());
				System.out.println((new Date()).toString() + " ClientWatche#sendMessage HEADER_PAGE");
				String doc = Integer.toString(pageStatus.getDocID());
				String page = Integer.toString(pageStatus.getPageID());

				// 次はMODEをDBから取得
				List<SwwDtoIF> dtoList = dm.getDto(loginDto, new PresentDao());
				PresentDto presentDto = null;
				System.out.println((new Date()).toString() + " dm.getDto(loginDto, new PresentDao().size()=" +  dtoList.size());
				if(0 < dtoList.size()){
					presentDto =  (PresentDto)dtoList.get(0);
				}
//				System.out.println((new Date()).toString() + " presentDto.getMode()=" +  presentDto.getMode());

				System.out.println((new Date()).toString() + " presentDto.getMode() null? " +  presentDto == null);
				
				// 次はDRAWをDBから取得
				List<DrawDto> drawDtoList = new ArrayList<DrawDto>();
				// ログイン時に何も描画されない場合があるため、データが有るかチェックする
				if(presentDto != null && presentDto.getDraw_e_ids()!=null && !presentDto.getDraw_e_ids().equals("")){
					System.out.println((new Date()).toString() + " " + userName + " presentDto.getDraw_e_ids()="+presentDto.getDraw_e_ids());
					DrawDto drawDtoTemp = null;
					String draw_e_ids[] = presentDto.getDraw_e_ids().split(",");
					//draw_e_idの分（描画がある分）だけ情報を取得する
					for(int i = 0 ; i < draw_e_ids.length ; i ++){
						// presentDtoを再利用する
						presentDto.setDraw_e_ids(draw_e_ids[i]);
						List<SwwDtoIF> drawDtoListTemp = dm.getDto(presentDto, new DrawDao());
//						System.out.println((new Date()).toString() + " draw_e_ids[i]="+draw_e_ids[i] + " size=" + drawDtoListTemp.size());
						if(0 < drawDtoListTemp.size()){
							Iterator<SwwDtoIF> itr = drawDtoListTemp.iterator();
							StringBuffer xy = new StringBuffer();
							while(itr.hasNext()){
								drawDtoTemp =  (DrawDto)itr.next();
								if(drawDtoTemp.getPoints()!=null && !drawDtoTemp.getPoints().equals("")){
									xy.append(drawDtoTemp.getPoints());
									// TODO カンマでの連結が複数箇所にあることは要再考
									xy.append(",");
								}
							}
							DrawDto drawDto = new DrawDto();
							drawDto.setColor(drawDtoTemp.getColor());
							drawDto.setThickness(drawDtoTemp.getThickness());
							drawDto.setPoints(xy.toString());
							drawDtoList.add(drawDto);

							System.out.println((new Date()).toString() + " " + userName + " ClientWatcher drawDto.getColor()="+drawDto.getColor());
							System.out.println((new Date()).toString() + " " + userName + " ClientWatcher drawDto.getThickness()="+drawDto.getThickness());
							System.out.println((new Date()).toString() + " " + userName + " ClientWatcher drawDto.getPoints()="+drawDto.getPoints());
						}
					}
				}


				// TODO 次はStickyをDBから取得
				/*
				List<NoteDataDto> noteDtoList = new ArrayList<NoteDataDto>();
				//Presentテーブルにイベントデータが有るかチェックする
				if(presentDto.getSticky_e_ids()!=null && !presentDto.getSticky_e_ids().equals("")){
					NoteDataDto noteDtoTemp = null;
					String sticky_e_ids[] = presentDto.getSticky_e_ids().split(",");
					//sticky_e_idsの分（テキストボックスがある分）だけ情報を取得する
					for(int i = 0 ; i < sticky_e_ids.length ; i ++){
						
						// 分解したイベントIDをpresentDtoにセットしてstick_eventテーブルを検索する
						presentDto.setSticky_e_ids(sticky_e_ids[i]);
						List<SwwDtoIF> noteDtoListTemp = dm.getDto(presentDto, new NoteDataDao());
//						
						System.out.println((new Date()).toString() + " sticky_e_ids[i]="+sticky_e_ids[i] + " size=" + noteDtoListTemp.size());
						if(0 < noteDtoListTemp.size()){
							Iterator<SwwDtoIF> itr = noteDtoListTemp.iterator();
							StringBuffer xy = new StringBuffer();
							while(itr.hasNext()){
								noteDtoTemp =  (NoteDataDto)itr.next();
							}
							NoteDataDto noteDto = new NoteDataDto();
							noteDto.setUser(noteDtoTemp.getUser());
							noteDto.setNum(noteDtoTemp.getNum());
							noteDto.setHeight(noteDtoTemp.getHeight());
							noteDto.setWidth(noteDtoTemp.getWidth());
							noteDto.setX(noteDtoTemp.getX());
							noteDto.setY(noteDtoTemp.getY());
							noteDto.setText(noteDtoTemp.getText());
							noteDtoList.add(noteDto);

						}
					}
				}
				*/				
				
				if(presentDto != null){
					// メッセージを送信する
					new PresentStatusNotifier(msgClient, 
							msgClient.getDestinationId(),
							"login", 
							Integer.toString(presentDto.getMode()), 
							doc, 
							page, 
							drawDtoList).start();
				}
			} else {
				System.out.println(new Date().toString() + " SESSION_PAGESTATUS has no pageStatOBj.");
				PageStatus pageStatus = new PageStatus();
				FlexContext.getServletContext().setAttribute(SESSION_PAGESTATUS, pageStatus);
			}

			// 自身をクライアントの切断を監視するリスナとしても登録する。
			msgClient.addMessageClientDestroyedListener(this);

		}catch (Exception e) {
			e.printStackTrace();
		}

	}

	@Override
	public void messageClientDestroyed(MessageClient msgClient) {
		// ユーザが切断したことを通知する。
		String userName = msgClient.getFlexSession().getUserPrincipal().getName();
//		sendMessage(msgClient.getDestinationId(), userName + " has left.");
		System.out.println(new Date().toString() + " " + userName + " has left.");
		// 明示的にセッションを破棄する。
		msgClient.getFlexSession().timeout();
	}



	class PresentStatusNotifier extends Thread {
		private MessageClient client;
		private String dest;
		private String operation;
		private String mode;
		private String page;
		private String doc;
		private Object data;


		PresentStatusNotifier(MessageClient client, String dest, String operation, String mode, String doc, String page, List draw) {
			this.client = client;
			this.dest = dest;
			this.operation = operation;
			this.mode = mode;
			this.page = page;
			this.doc = doc;
			this.data = draw;
		}


		@Override
		public void run() {
			// メッセージの受信漏れを防ぐため遅延させる。
			System.out.println((new Date()).toString() + " START PresentStatusNotifier run()");
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
			}

			System.out.println((new Date()).toString() + " operation=" + operation);
			MessageBroker msgBroker = MessageBroker.getMessageBroker(null);
//			System.out.println((new Date()).toString() + " START 1");
			AsyncMessage msg = new AsyncMessage();
//			System.out.println((new Date()).toString() + " START 2");
			msg.setMessageId(UUIDUtils.createUUID());
//			System.out.println((new Date()).toString() + " START 3");
			msg.setTimestamp(System.currentTimeMillis());
//			System.out.println((new Date()).toString() + " START 4");
			msg.setClientId(client.getClientId());
//			System.out.println((new Date()).toString() + " START 5");
			// TODO サーバーからの送信　none
			msg.setHeader(HEADER_USER, "none");
//			System.out.println((new Date()).toString() + " START 6");
			msg.setHeader(HEADER_ROOM, dest);
//			System.out.println((new Date()).toString() + " START 7");
			msg.setHeader(HEADER_OPERATION, operation);
//			System.out.println((new Date()).toString() + " START 8 doc = " + doc);
			msg.setHeader("doc", doc);

//			System.out.println((new Date()).toString() + " START 9 page = " + page);
			msg.setHeader("page", page);
//			System.out.println((new Date()).toString() + " START 9.1 mode = " + mode);
			msg.setHeader("mode", mode);
//			System.out.println((new Date()).toString() + " START 10");
//			System.out.println((new Date()).toString() + " START 10.1 data = " + data);
			msg.setBody(data);
//			System.out.println((new Date()).toString() + " START 11");

			msgBroker.routeMessageToMessageClient(msg, client);

			System.out.println((new Date()).toString() + " END PresentStatusNotifier run()");
		}


	}
}
